package com.wt.springsamples.config;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

@Configuration
public class HttpClientConfig {

    @Bean
//    @ConfigurationProperties("http.client")
    public HttpClientProperties httpClientProperties(){ return new HttpClientProperties(); }

    @Bean
    public CloseableHttpClient httpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        HttpClientProperties httpClientProp = httpClientProperties();
        return HttpClients.custom()
                .setConnectionManager(buildClientConnManager(httpClientProp))
                .setRetryHandler(buildRequestRetryHandler(httpClientProp))
                .setDefaultRequestConfig(buildRequestConfig(httpClientProp))
                .build();
    }
    @Bean
    public PoolingHttpClientConnectionManager buildClientConnManager(HttpClientProperties httpClientProp) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        SSLContext sslContext = SSLContexts.custom()
//                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
                .loadTrustMaterial(null,(chain,authType)->true)
                .build();

        //配置同时支持HTTP和HTPPS
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https",new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE))
                .build();
        PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        clientConnectionManager.setMaxTotal(httpClientProp.getPool().getMaxTotal());
        clientConnectionManager.setDefaultMaxPerRoute(httpClientProp.getPool().getDefaultMaxPerRoute());
        return clientConnectionManager;
    }

    private RequestConfig buildRequestConfig(HttpClientProperties httpClientProp) {
        return RequestConfig.custom()
                .setConnectionRequestTimeout(httpClientProp.getRequest().getConnectionRequestTimeout())
                .setSocketTimeout(httpClientProp.getRequest().getSocketTimeout())
                .setConnectTimeout(httpClientProp.getRequest().getConnectTimeout())
                .setCookieSpec(CookieSpecs.STANDARD_STRICT)//自动保存cookie并发送,第一次请求cookie为null,后续请求会携带cookie
//                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)//禁用cookie,请求不携带cookie
                .build();
    }

    private HttpRequestRetryHandler buildRequestRetryHandler(HttpClientProperties httpClientProp) {
        return (exception, executionCount, context) -> {
            //若失败次数达到3次，则不再重试
            if (executionCount >= httpClientProp.getRequest().getMaxRetryTime()) {
                return false;
            }
            //若报服务器无响应异常，则重试
            if (exception instanceof NoHttpResponseException) {
                return true;
            }
            //若报SSL握手异常，不重试
            if (exception instanceof SSLHandshakeException) {
                return false;
            }
            //若报IO中断异常，不重试
            if (exception instanceof InterruptedIOException) {
                return false;
            }
            //若报未知主机异常，不重试
            if (exception instanceof UnknownHostException) {
                return false;
            }
            //若报连接超时异常，不重试
            if (exception instanceof SSLException) {
                return false;
            }
            //若请求是幂等的，则重试
            HttpClientContext clientContext = HttpClientContext.adapt(context);
            HttpRequest request = clientContext.getRequest();
            return !(request instanceof HttpEntityEnclosingRequest);
        };
    }
}
